package com.sky.d_fork_jion;

import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveTask;
import java.util.concurrent.TimeUnit;

/**
 * http://ifeve.com/fork-join-6/
 * 实现取消ForkJoinTask对象的例子。你将查找数在数组中的位置。
 * 第一个找到这个数的任务将取消剩下的任务（未找到这个数的任务）。
 * 由于Fork/Join框架并没有提供这种功能，所以，你将实现一个辅助类来做这个取消功能
 * 
 * 
 * 这个类将查找在整数数组的元素块中的数
 * @Author:hjt
 */
//TODO 没看懂
public class SearchNumberTask extends RecursiveTask<Integer>{

	private static final long serialVersionUID = 1L;
	
	//声明一个私有的、int类型的数字数组
	private int[] numbers;
	
	//声明两个私有的、int类型的属性start和end。这些属性将决定任务要处理的数组的元素
	private int start, end;
	
	//声明一个私有的、int类型的属性number，它将存储你将要查找的数
	private int number;
	
	//声明一个私有的、TaskManager类型的属性manager。你将使用这个对象来取消所有任务
	private TaskManager manager;
	
	//声明一个私有的、int类型的常量并初始化它为值-1。当任务没有找到这个数时，它将作为任务的返回值
	private final static int NOT_FOUND = -1;
	
	//实现这个类的构造器来初始化它的属性
	public SearchNumberTask(int[] numbers, int start, int end,
			int number, TaskManager manager) {
		this.numbers = numbers;
		this.start = start;
		this.end = end;
		this.number = number;
		this.manager = manager;
	}

	@Override
	protected Integer compute() {
		//写入一条信息（start和end属性值）到控制台表明这个方法的开始
		System.out.printf("Task: " + start + ":" + end + "\n");
		
		int ret;
		//如果start和end之差大于10（这个任务将处理超过10个元素的数组），调用launchTasks()方法，将这个任务的工作拆分成两个任务
		if((end - start) > 10){
			ret = launchTasks();
		} else {
			//否则，这个任务调用lookForNumber()方法来查找在数组块中的数
			ret = lookForNumber();
		}
		//返回结果 ret
		return ret;
	}

	private int lookForNumber() {
		// 对于任务要处理的元素块中的所有元素，将你想要查找的数与存储在元素中的值进行比较。
		// 如果他们相等，写入一条信息到控制台表明这种情形，使用TaskManager对象的cancelTasks()方法来取消所有任务，
		// 并返回你已经找到的这个数对应元素的位置
		
		for(int i = start; i<end; i++){
			if(numbers[i] == number){
				System.out.printf("Task number %d found in position %d\n", number, i + "\n");
				manager.cancelTask(this);
				return i;
			}
			
			try {
				//睡一秒
				TimeUnit.SECONDS.sleep(1);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		
		return NOT_FOUND;
	}

	/**
	 * 首先，将这个任务要处理的数块分成两个部分，然后，创建两个Task对象来处理它们
	 */
	private int launchTasks() {
		
		int mid = (start + end)/2;
		SearchNumberTask t1 = new SearchNumberTask(numbers, start, mid, number, manager);
		SearchNumberTask t2 = new SearchNumberTask(numbers, mid, end, number, manager);
		
		//添加这个任务到TaskManager对象中
		manager.addTask(t1);
		manager.addTask(t2);
		
		//使用fork()方法异步执行这两个任务
		t1.fork();
		t2.fork();
		
		//等待这个任务的结束，返回第一个任务的结果（如果它不等于-1），或第二个任务的结果
		int returnValue;
		
		returnValue = t1.join();
		if(returnValue != -1){
			return returnValue;
		}
		
		returnValue = t2.join();
		return returnValue;
	}
	
	//实现writeCancelMessage()方法，当任务取消时，写一条信息到控制台
	public void writeCancelMessage() {
		System.out.printf("Task：Canceld task from %d to %d", start, end + "\n");

	}
	
	public static void main(String[] args) {
		//使用ArrayGenerator类，创建一个有1000个数字的数组
		ArrayGenerator generator = new ArrayGenerator();
		int[] array = generator.generateArray(100);
		
		//创建一个TaskManager对象
		TaskManager manager = new TaskManager();
		
		//使用默认的构造器创建一个ForkJoinPool对象
		ForkJoinPool pool = new ForkJoinPool();
		
		//创建一个Task对象来处理前面生成的数组
		SearchNumberTask task = new SearchNumberTask(array, 0, 1000, 5, manager);
		
		//使用execute()方法，在池中异步执行任务
		pool.execute(task);
		
		//使用shutdown()方法关闭这个池
		pool.shutdown();
		
		//使用ForkJoinPool类的awaitTermination()方法，等待任务的结束
		try {
			pool.awaitTermination(1, TimeUnit.DAYS);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
		//写入一条信息到控制台，表明程序的结束
		System.out.printf("main: the program has finished\n");
	}

}
/**
 cancel
 	开始执行任务前，可以取消执行
 	不能取消池中运行或等待的所有任务
 	不能取消一个正在执行的任务
 	
 	
 	例子：
 		1.创建ArrayGenerator类
 		2.创建一个TaskManager类
 		3.实现SearchNumberTask类，指定它继承参数化为Integer类型的RecursiveTask类
 */
